import java.util.PriorityQueue;

//首先需要有一个类来描述可以执行的任务
class MyTask implements Comparable<MyTask>{
    //定义一个可以执行的任务
    private Runnable runnable;
    //定义一个任务执行的时间
    private long time;
    public MyTask(Runnable runnable, long delay){
        this.runnable = runnable;
        this.time = System.currentTimeMillis() + delay;
    }

    public Runnable getRunnable() {
        return runnable;
    }

    public long getTime() {
        return time;
    }

    @Override
    public int compareTo(MyTask o) {
        return (int) (this.time - o.time);
    }
}
public class Demo_MyTimer2 {
    //首先需要有一个可以存放任务的队列，队列可以传一个比较的方法，但是因为任务里面定义的都是私有属性，所以只能传可以比较的对象
    private PriorityQueue<MyTask> queue = new PriorityQueue<>();
    private Object locker = new Object();
    //需要定义一个schedule方法，用于在队列中添加任务
    public void schedule(Runnable runnable, long delay){
        //考虑到不同线程会调用schedule和扫描任务队列，针对队列进行修改，考虑线程安全 - 加锁
        synchronized (locker){
            MyTask task = new MyTask(runnable, delay);
            queue.offer(task);
            //添加了任务，要唤醒线程t,提示可以取任务了
            locker.notify();
        }
    }
    //使用构造方法定义定时器的时候，需要有一个线程一直扫描任务
    public Demo_MyTimer2(){
        Thread t = new Thread(() -> {
            //因为线程需要一直扫描，因此使用while循环
            while(true){
                try{
                    synchronized (locker){
                        //wait被唤醒之后，还需要再确认一下条件是否满足，因此使用while
                        while(queue.isEmpty()){
                            //如果队列是空的，那么应该等待其它线程调用schedule方法，在队列里面添加可执行的任务
                            locker.wait();
                        }
                        MyTask task = queue.peek();
                        long currentTime = System.currentTimeMillis();
                        //如果当前的时间到了执行任务的时间，那么就可以执行任务了
                        if(currentTime >= task.getTime()){
                            task.getRunnable().run();
                            //执行完毕后，从队列中删除任务
                            queue.poll();
                        }else{
                            //如果还没有到任务执行时间，就可以让线程休眠，没必要一直忙等
                            locker.wait(task.getTime() - currentTime);
                        }
                    }
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        });
        //线程调用完了之后，必须要再定时器里面启动，否则不起作用
        t.start();
    }
}

class Test2{
    public static void main(String[] args) {
        Demo_MyTimer2 timer2 = new Demo_MyTimer2();
        timer2.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("3000");
            }
        }, 3000);
        timer2.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("2000");
            }
        }, 2000);
        timer2.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("1000");
            }
        }, 1000);
        System.out.println("代码开始执行");
    }
}
